package com.push.spider.utils;

import com.alibaba.fastjson.JSONObject;
import com.push.common.config.RuoYiConfig;
import com.push.common.utils.*;
import com.push.common.utils.httpclient.HttpClientUtil;
import com.push.framework.web.domain.server.Sys;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile;

import javax.activation.MimetypesFileTypeMap;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class UrlUtils {
    static String[] jsJumps = {
            "window.location.href",
            "location.href",
            "window.top.location",
            "top.location",
            "window.self.location",
            "self.location",
            "window.parent.location.href",
            "parent.location.href"
    };

    /**
     * 将img标签中的src进行二次包装
     * @param content 内容
     * @param baseUrl 当期URL
     * @return
     */
    public static String repairContent(String content,String baseUrl){
        String patternStr="<img\\s*([^>]*)\\s*src=\\\"(.*?)\\\"\\s*([^>]*)>";
        Pattern pattern = Pattern.compile(patternStr,Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(content);
        String result = content;
        while(matcher.find()) {
            String src = StringUtils.trimAllWhitespace(matcher.group(2));
            result = result.replaceAll(src,buildUrl(baseUrl,src));
        }
        return result;
    }

    public static String getContentType(String fileUrl) {
        String contentType = null;
        try {
            contentType = new MimetypesFileTypeMap().getContentType(new File(fileUrl));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return contentType;
    }

    /**
     * 将img标签中的src进行二次包装
     * @param content 内容
     * @param urls 当期URL
     * @return
     */
    public static String repairDownloadContent(String content, List<String> urls){
        String patternStr="<img\\s*([^>]*)\\s*src=\\\"(.*?)\\\"\\s*([^>]*)>";
        Pattern pattern = Pattern.compile(patternStr,Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(content);
        String result = content;
        int idx = 0;
        while(matcher.find()) {
            String src = StringUtils.trimAllWhitespace(matcher.group(2));
            if (null != urls.get(idx)){
                result = result.replaceAll(src,urls.get(idx));
            }
            idx++;
        }
        return result;
    }

    /**
     * 如果匹配的对象（视频，音频等）数量M大于urls的数量N，只替换匹配数量的前N个
     */
    public static String repairDownloadObjContent(String content, List<String> urls, String patternStr){
        Pattern pattern = Pattern.compile(patternStr, Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(content);
        String result = content;
        int idx = 0;
        while(matcher.find()) {
            String src = StringUtils.trimAllWhitespace(matcher.group(2));
            if (urls.size()>idx && null != urls.get(idx)){
                result = result.replaceAll(src,urls.get(idx));
            }
            idx++;
        }
        return result;
    }

    public static List<String> downloadFilesToMinio(List<String> urls, MinioUtil minioUtil) throws IOException {
        List<String> newUrls = new ArrayList<>();
        if (urls.size() > 0){
            for (String url : urls) {
                if(url.trim().isEmpty()){
                    newUrls.add("");
                    continue;
                }
                //先暂存到本地（oss.local.upload-file-path设置的位置），同时重命名
                String filePath = HttpClientUtil.downLoadFromUrl(url, SnowflakeIdWorker.generateId()+ LinkHelper.getTypeByExtenssion(url), RuoYiConfig.getProfile());
                File file = new File(filePath);
                MultipartFile cMultiFile = new MockMultipartFile("file", file.getName(), UrlUtils.getContentType(filePath), new FileInputStream(file));
                //上传minio，返回新路径
                String objectName = minioUtil.upload(cMultiFile);
                //删除本地暂存文件
                Path path = Paths.get(filePath);
                Files.deleteIfExists(path);
                newUrls.add(minioUtil.preview(objectName));
            }
        }
        return newUrls;
    }

    public static JSONObject downloadFilesToMinioV2(List<String> urls, MinioUtil minioUtil) throws IOException {
        List<String> newUrls = new ArrayList<>();
        List<String> fileSizeList = new ArrayList<>();
        if (urls.size() > 0){
            for (String url : urls) {
                if(url.trim().isEmpty()){
                    newUrls.add("");
                    fileSizeList.add("");
                    continue;
                }
                //先暂存到本地（oss.local.upload-file-path设置的位置），同时重命名
                String filePath = HttpClientUtil.downLoadFromUrl(url, SnowflakeIdWorker.generateId()+ LinkHelper.getTypeByExtenssion(url), RuoYiConfig.getProfile());
                System.out.println("本地缓存文件：" + filePath);
                File file = new File(filePath);
                long fileSize = file.length();
                MultipartFile cMultiFile = new MockMultipartFile("file", file.getName(), UrlUtils.getContentType(filePath), new FileInputStream(file));
                //上传minio，返回新路径
                String objectName = minioUtil.upload(cMultiFile);
                //删除本地暂存文件
                Path path = Paths.get(filePath);
                Files.deleteIfExists(path);
                newUrls.add(minioUtil.preview(objectName));
                fileSizeList.add(formatFileSize(fileSize));

                //System.out.println("new:" + minioUtil.preview(objectName));
                //System.out.println("size:" + fileSize + " | " + formatFileSize(fileSize));
            }
        }
        JSONObject retObj = new JSONObject();
        retObj.put("newUrls", newUrls);
        retObj.put("fileSizeList", fileSizeList);
        return retObj;
    }

    public static String downloadFileToMinio(String url, MinioUtil minioUtil){
        String newUrl = "";
        if (StringUtils.isEmpty(url)){
            return newUrl;
        }
        try{
            //下载到本地
            String filePath = HttpClientUtil.downLoadFromUrl(url, SnowflakeIdWorker.generateId()+ LinkHelper.getTypeByExtenssion(url), RuoYiConfig.getProfile());
            File file = new File(filePath);
            MultipartFile cMultiFile = new MockMultipartFile("file", file.getName(), UrlUtils.getContentType(filePath), new FileInputStream(file));
            String objectName = minioUtil.upload(cMultiFile);
            Path path = Paths.get(filePath);
            Files.deleteIfExists(path);
            newUrl = minioUtil.preview(objectName);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally{
            return newUrl;
        }
    }

    public static List<String> downloadFileToMinioV2(String url, MinioUtil minioUtil){
        List<String> retStrList = Arrays.asList("", "");
        String newUrl = "";
        if (StringUtils.isEmpty(url)){
            return retStrList;
        }
        try{
            //下载到本地
            String filePath = HttpClientUtil.downLoadFromUrl(url, SnowflakeIdWorker.generateId()+ LinkHelper.getTypeByExtenssion(url), RuoYiConfig.getProfile());
            File file = new File(filePath);
            long fileSize = file.length();
            MultipartFile cMultiFile = new MockMultipartFile("file", file.getName(), UrlUtils.getContentType(filePath), new FileInputStream(file));
            String objectName = minioUtil.upload(cMultiFile);
            Path path = Paths.get(filePath);
            Files.deleteIfExists(path);
            newUrl = minioUtil.preview(objectName);
            retStrList.set(0, newUrl);
            retStrList.set(1, formatFileSize(fileSize));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally{
            return retStrList;
        }
    }

    public static List<String> praseUrlFromString(String html, String baseUrl){
        List<String> urls = new ArrayList<>();
        String patternStr="<img\\s*([^>]*)\\s*src=\\\"(.*?)\\\"\\s*([^>]*)>";
        Pattern pattern = Pattern.compile(patternStr,Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(html);
        while(matcher.find()) {
            String src = StringUtils.trimAllWhitespace(matcher.group(2));
            urls.add(buildUrl(baseUrl,src));
        }
        return urls;
    }

    public static List<String> praseObjUrlFromString(String html, String baseUrl, String patternStr){
        List<String> urls = new ArrayList<>();
        Pattern pattern = Pattern.compile(patternStr,Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(html);
        while(matcher.find()) {
            String src = StringUtils.trimAllWhitespace(matcher.group(2));
            urls.add(buildUrl(baseUrl,src));
        }
        return urls;
    }


    /**
     * 根据大小拼接 "B", "KB", "MB", "GB"
     * @param fileSize
     * @return
     */
    public static String formatFileSize(long fileSize) {
        if (fileSize <= 0) {
            return "0B";
        }
        final String[] units = new String[]{"B", "KB", "MB", "GB"};
        int digitGroups = (int) (Math.log10(fileSize) / Math.log10(1024));
        return String.format("%.2f %s", fileSize / Math.pow(1024, digitGroups), units[digitGroups]);
    }

    /**
     * 通过url获取文件大小
     * @return
     */
    public static long getFileSizeByUrl(String url){
        long fileSize = -1L;
        if (StringUtils.isEmpty(url)){
            return fileSize;
        }
        try{
            //下载到本地
            String filePath = HttpClientUtil.downLoadFromUrl(url, SnowflakeIdWorker.generateId()+ LinkHelper.getTypeByExtenssion(url), RuoYiConfig.getProfile());
            File file = new File(filePath);
            fileSize = file.length();

            //清除本地文件
            Path path = Paths.get(filePath);
            Files.deleteIfExists(path);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally{
            return fileSize;
        }
    }

    public static String getFileSizeByUrlWithFormat(String url){
        long fileSize = getFileSizeByUrl(url);
        return formatFileSize(fileSize);
    }

    /**
     * 通过文件名或url链接获取后缀
     */
    public static String getFileExtendByName(String fileName){
        String[] strArr = StringUtils.split(fileName, ".");
        if(strArr.length > 0 && strArr[strArr.length - 1].length() <= 4){
            return strArr[strArr.length - 1];
        }else{
            return "";
        }
    }

    public static String buildUrl(String curUrl, String srcUrl) {
        if(StringUtils.isEmpty(srcUrl)){
            return srcUrl;
        }
        if (isFirstAlt(srcUrl)) {
            return firstAltReplaceUrl(srcUrl, curUrl);
        }
        if ("#".equals(srcUrl)) {
            if (!"/".equals(curUrl.substring(curUrl.length() - 1))) {
                curUrl += "/";
            }
        }
        srcUrl = srcUrl.replaceAll("\\\\", "/");
        if (srcUrl.startsWith("http://") || srcUrl.startsWith("https://")
                || srcUrl.startsWith("HTTP://") || srcUrl.startsWith("HTTPS://") || srcUrl.startsWith("data:")) {
            return srcUrl;
        }
        String startsWith = "../";
        if (srcUrl.startsWith(startsWith)) {
            curUrl = checkUrl(curUrl);
            while (srcUrl.startsWith(startsWith)) {
                curUrl = checkUrl(curUrl);
                srcUrl = srcUrl.replaceFirst(startsWith, "");
            }
            return curUrl + "/" + srcUrl;
        } else if(srcUrl.startsWith("/")) {
            curUrl = checkUrl(curUrl);
            curUrl = checkUrl(curUrl);
            return domainUrl(curUrl) + srcUrl;
        } else {
            if (srcUrl.startsWith("./")) {
                srcUrl = srcUrl.replaceFirst("./", "");
            }
            curUrl = checkUrl(curUrl);
            return curUrl + "/" + srcUrl;
        }
    }

    public static boolean isFirstAlt(String url){
        if (url.startsWith("@")) {
            return true;
        } else {
            return false;
        }
    }

    public static String firstAltReplaceUrl(String url, String baseUrl){
        if(isFirstAlt(url)) {
            url = url.replaceFirst("@", domainUrl(baseUrl));
        }
        return url;
    }

    /**
     * 获取主域名地址
     * @param domain
     * @return
     */
    public static String domainUrl(String domain) {
        if (domain.startsWith("http://") || domain.startsWith("HTTP://")) {
            String temp = domain.replaceFirst("http://", "").replaceFirst("HTTP://", "");
            if (temp.indexOf("/") > -1) {
                domain = "http://" + temp.substring(0, temp.indexOf("/"));
            } else {
                return domain;
            }
        } else if (domain.startsWith("https://") || domain.startsWith("HTTPS://")) {
            String temp = domain.replaceFirst("https://", "").replaceFirst("HTTPS://", "");
            if (temp.indexOf("/") > -1) {
                domain = "https://" + temp.substring(0, temp.indexOf("/"));
            } else {
                return domain;
            }
        } else if (domain.startsWith("//")) {
            String temp = domain.replace("//", "");
            if (temp.indexOf("/") > -1) {
                domain = "//" + temp.substring(0, temp.indexOf("/"));
            } else {
                return domain;
            }
        } else {
            if (domain.indexOf("/") > -1) {
                domain = domain.substring(0, domain.indexOf("/"));
            } else {
                return domain;
            }
        }
        return domain;
    }

    public static String checkUrl(String url){
        String profix = url.substring(0, url.lastIndexOf("/"));
        if (!"http:/".equals(profix) && !"https:/".equals(profix) && !"/".equals(profix) && !"HTTP:/".equals(profix) && !"HTTPS:/".equals(profix)) {
            url = url.substring(0, url.lastIndexOf("/"));
        }
        return url;
    }

    public static String urlToUtf8(String s) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if (c >= 0 && c <= 255) {
                if (c == 32) {
                    sb.append("%" + Integer.toHexString(32).toUpperCase());
                } else {
                    sb.append(c);
                }
            } else {
                byte[] b;
                try {
                    b = String.valueOf(c).getBytes("utf-8");
                } catch (Exception ex) {
                    System.out.println(ex);
                    b = new byte[0];
                }
                for (int j = 0; j < b.length; j++) {
                    int k = b[j];
                    if (k < 0) {
                        k += 256;
                    }
                    sb.append("%" + Integer.toHexString(k).toUpperCase());
                }
            }
        }
        return sb.toString();
    }

    /**
     * 是否存在重定向
     * @param url
     * @param resHtml
     * @return
     */
    public static String isUrlRedirectUrl(HttpURLConnection connection, String url, String resHtml){
        /**
         * meta重定向
         */
        String redirectUrl = metaUrlRedirectUrl(url, resHtml);
        if (!StringUtils.isEmpty(redirectUrl)) {
            return redirectUrl;
        }
        /**
         * js重定向
         */
        redirectUrl = jsUrlRedirectUrl(url, resHtml);
        if (!StringUtils.isEmpty(redirectUrl)) {
            return redirectUrl;
        }

        /**
         * 302跳转
         */
        redirectUrl = redirectUrl(connection);
        if (!StringUtils.isEmpty(redirectUrl)) {
            return redirectUrl;
        }

        /**
         * ajax跳转
         */
        redirectUrl = ajaxUrlRedirectUrl(url, resHtml);
        if (!StringUtils.isEmpty(redirectUrl)) {
            return redirectUrl;
        }
        return redirectUrl;
    }

    public static String redirectUrl(HttpURLConnection connection) {
        String url = "";
        try {
            if (connection.getResponseCode() == 302) {
                String redirectUrl = connection.getHeaderField("Location");
                if(redirectUrl != null && !redirectUrl.isEmpty()) {
                    return redirectUrl;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return url;
    }

    /**
     * meta重定向
     * @param url
     * @param resHtml
     * @return
     */
    public static String metaUrlRedirectUrl(String url, String resHtml) {
        String redirectUrl = "";
        Document doc = Jsoup.parse(resHtml);
        Element element = doc.select("meta[HTTP-EQUIV=REFRESH]").first();
        if (element != null) {
            redirectUrl = element.attr("CONTENT");
            String startWith = "URL=";
            if (redirectUrl.indexOf(startWith) > -1) {
                redirectUrl = redirectUrl.substring(redirectUrl.indexOf(startWith), redirectUrl.length());
                redirectUrl = redirectUrl.replaceFirst(startWith, "");
            } else {
                startWith = "url=";
                if (redirectUrl.indexOf(startWith) > -1) {
                    redirectUrl = redirectUrl.substring(redirectUrl.indexOf(startWith), redirectUrl.length());
                    redirectUrl = redirectUrl.replaceFirst(startWith, "");
                }
            }

            if (!StringUtils.isEmpty(redirectUrl)) {
                return UrlUtils.buildUrl(url, redirectUrl);
            }
        }
        return redirectUrl;
    }

    /**
     * js重定向
     * @return
     */
    public static String jsUrlRedirectUrl(String url, String resHtml) {
        String redirectUrl = "";
        Document doc = Jsoup.parse(resHtml);
        Elements eles = doc.select("script");

        for (Element element : eles) {
            String jsData = element.data();
            jsData = jsData.trim();
            for (String jump : jsJumps) {
                if (jsData.startsWith(jump)) {
                    redirectUrl = startJsUrl(jsData);
                }
            }
        }
        if (!StringUtils.isEmpty(redirectUrl)) {
            return UrlUtils.buildUrl(url, redirectUrl);
        }
        return redirectUrl;
    }

    public static String ajaxUrlRedirectUrl(String url, String html) {
        String redirectUrl = "";
        String regex = "^[a-z|A-Z|0-9]*.html$";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(html);
        while (matcher.find()) {
            redirectUrl = matcher.group(0);
            break;
        }
        if (url.contains("paper.eznews.cn/ajax")) {
            redirectUrl = "/paperlist/" + redirectUrl;
        }
        if (!StringUtils.isEmpty(redirectUrl)) {
            return UrlUtils.buildUrl(url, redirectUrl);
        }
        return redirectUrl;
    }

    /**
     * 正则表达式获取js跳转地址
     * @param html
     * @return
     */
    public static String startJsUrl(String html){
        String url = "";
        String regex = "^(location.href.*?(\"|\')"
                + "|window.location.href.*?(\"|\')"
                + "|window.top.location.*?(\"|\')"
                + "|top.location.*?(\"|\')"
                + "|window.parent.location.href.*?(\"|\')"
                + "|parent.location.href.*?(\"|\')"
                + "|window.self.location.*?(\"|\')"
                + "|self.location.*?(\"|\')" + ")(.*?)((\"|\'))";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(html);
        while (matcher.find()) {
            url = matcher.group(10);
            break;
        }
        return url;
    }

    /**
     * 正则表达式获取js标题跳转地址
     * @param jsFunctionName
     * @param value
     * @return
     */
    public static String titleUrl(String jsFunctionName, String value) {
        String url = "";
        String regex = "(" + jsFunctionName + "\\((\"|\'))(.*?)(\"|\')";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(value);
        while (matcher.find()) {
            url = matcher.group(3);
            break;
        }
        return url;
    }

    public static String urlSuffix(String url) {
        if (url.lastIndexOf(".") > -1) {
            return url.substring(url.lastIndexOf("."));
        } else {
            return url;
        }
    }
}
